#pragma once
#include<unistd.h>
#include<iostream>
#include<time.h>
#include<stdarg.h>
#include<fstream>
#include<string.h>
#include<pthread.h>
enum
{
    DEBUG = 1,
    INFO,
    WARNING,
    ERROR,
    FATAL
};
const std::string logfile = "log.txt";
pthread_mutex_t _mutex;
#define SCREEN_TYPE 1
#define FILE_TYPE 2
std::string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "DEBUG";
        break;
    case INFO:
        return "INFO";
        break;
    case ERROR:
        return "ERROR";
        break;
    case WARNING:
        return "WARNING";
        break;
    case FATAL:
        return "FATAL";
        break;
    default:
        return "UNKONW";
        break;
    }
}
std::string GetTime()
{
    time_t now = time(nullptr);
    struct tm *curr = localtime(&now);
    char buf[128];
    snprintf(buf, sizeof(buf), "%d-%02d-%02d %02d:%02d:%02d",
             curr->tm_year+1900,
             curr->tm_mon+1,
             curr->tm_mday,
             curr->tm_hour,
             curr->tm_min,
             curr->tm_sec);
    return buf;
}
class LockGuard
{
public:
    LockGuard(pthread_mutex_t* td):_td(td)
    {
        pthread_mutex_lock(_td);
    }
    ~LockGuard()
    {
        pthread_mutex_unlock(_td);
    }

private:
    pthread_mutex_t *_td;
};
class Logmessage
{
public:
    std::string _level;
    pid_t _id;
    std::string _filename;
    int _filenumber;//行号
    std::string _curr_time;
    std::string _message_info;
};
class Log
{
public:
    Log(const std::string& filename=logfile):_logfile(filename)
    {}
    void Enable(int type)
    {
        _type = type;
    }
    void FlushToScreen(Logmessage& lg)
    {
        printf("[%s][%d][%s][%d][%s] %s", lg._level.c_str(), lg._id, lg._filename.c_str(), lg._filenumber, lg._curr_time.c_str(), lg._message_info.c_str());

    }
    void FlushToFile(Logmessage& lg)
    {
        std::ofstream t(_logfile,std::ios::app);
        if(!t.is_open())
            return;
        char logtxt[1024];
        snprintf(logtxt,sizeof(logtxt),"[%s][%d][%s][%d][%s] %s", lg._level.c_str(), lg._id, lg._filename.c_str(), lg._filenumber, lg._curr_time.c_str(), lg._message_info.c_str());
        t.write(logtxt, strlen(logtxt));
        t.close();
    }
    void FlushLog(Logmessage& lg)
    {
        LockGuard ld(&_mutex);
        // 此处可以加过滤，本代码没加
        if(_type==SCREEN_TYPE)
        {
            FlushToScreen(lg);
        }
        else if(_type==FILE_TYPE)
        {
            FlushToFile(lg);
        }
    }

    void logmessage(int level,std::string filename,int filenumber,const char* format,...)
    {
        Logmessage lg;
        lg._level = LevelToString(level);
        lg._id = getpid();
        lg._filename = filename;
        lg._filenumber = filenumber;
        lg._curr_time = GetTime();
        va_list ap;
        va_start(ap, format);
        char info[512];
        vsnprintf(info, sizeof(info), format, ap);
        va_end(ap);
        lg._message_info = info;
        FlushLog(lg);
    }
    ~Log(){}
private:
    int _type=SCREEN_TYPE;
    std::string _logfile;
};
Log lg;
#define LOG(level,format,...) do{lg.logmessage(level, __FILE__, __LINE__, format, ##__VA_ARGS__);}while (0)
#define EnableScreen() do{ lg.Enable(SCREEN_TYPE);} while (0)
#define EnableFILE() do{ lg.Enable(FILE_TYPE);} while (0)